﻿using System;
using System.Collections.Generic;
using System.Linq;
using CNav.Common;
using CNav.DataEntity;
using CNav.Domain;
using CNav.Domain.Admin;

namespace CNav.Business.Services
{
    public interface IUiService
    {
        ResponseData<List<DataSource>> GetDataSourceList();
        ResponseData<DataSource> GetDataSourceById(int id);
        ResponseData<bool> AddDataSource(DataSource dataSource);
        ResponseData<DataSource> UpdateDataSource(DataSource dataSource);
        ResponseData<bool> DeleteDataSource(int id);

        ResponseData<List<Form>> GetFormList();
        ResponseData<Form> GetFormById(int id);
        ResponseData<bool> AddForm(Form form);
        ResponseData<Form> UpdateForm(Form form);
        ResponseData<bool> DeleteForm(int id);

        ResponseData<List<DataValue>> GetDataValueList();
        ResponseData<List<DataValue>> GetDataValueByDataList(int dataSourceId);
        ResponseData<DataValue> GetDataValueById(int id);
        ResponseData<bool> AddDataValue(DataValue form);
        ResponseData<DataValue> UpdateDataValue(DataValue form);
        ResponseData<bool> DeleteDataValue(int id);

        ResponseData<List<FormDesign>> GetCustomFormList(int id);
        ResponseData<FormDesign> GetCustomFormById(int id);
        ResponseData<bool> AddCustomForm(FormDesign formDetail);
        ResponseData<FormDesign> UpdateCustomForm(FormDesign formDetail);
        ResponseData<bool> DeleteFormDetail(int id);

        ResponseData<List<Control>> GetControlList();
        ResponseData<List<RenderControl>> GetCustomFormControls(int formId);
        ResponseData<List<DataValue>> GetDataSourceForCustomFormControls(int datasourceId);
    }

    public class UiService : ServiceBase, IUiService
    {
        #region DataSource

        public ResponseData<List<DataSource>> GetDataSourceList()
        {
            var response = new ResponseData<List<DataSource>>();
            var result = Context.Get<DataSourceDto>().ToList();

            response.Data = result.Select(ds => new DataSource { ID = ds.ID, Name = ds.Name.ToUpper() }).ToList();

            return response;
        }

        public ResponseData<DataSource> GetDataSourceById(int id)
        {
            var response = new ResponseData<DataSource>();
            var result = Context.Get<DataSourceDto>(ds => ds.ID == id).ToList().FirstOrDefault();

            if (result != null)
            {
                response.Data = new DataSource { ID = result.ID, Name = result.Name };
                return response;
            }

            response.Error = new[] { "Invalid DataSource id" };
            return response;
        }

        public ResponseData<bool> AddDataSource(DataSource dataSource)
        {
            var response = new ResponseData<bool>();

            //TODO: Add validation logic for DataSource
            //if valid then
            var dataSourceDto = new DataSourceDto();
            dataSourceDto.Name = dataSource.Name.ToUpper();

            Context.Repository<DataSourceDto>().Add(dataSourceDto);
            Context.Commit();

            response.Data = true;
            return response;
        }

        public ResponseData<DataSource> UpdateDataSource(DataSource dataSource)
        {
            var response = new ResponseData<DataSource>();

            //TODO: Add validation logic for DataSource
            //if valid then

            DataSourceDto dataSourceDto = Context.Get<DataSourceDto>(p => p.ID == dataSource.ID).ToList().FirstOrDefault();

            if (dataSourceDto != null)
            {
                dataSourceDto.Name = dataSource.Name.ToUpper();

                Context.Repository<DataSourceDto>().Update(dataSourceDto);
                Context.Commit();
                response = GetDataSourceById(dataSource.ID);

                return response;
            }
            response.Error = new[] { "DataSource provided does not exist." };
            return response;
        }

        public ResponseData<bool> DeleteDataSource(int id)
        {
            var response = new ResponseData<bool>();

            var dataSourceDto = Context.Get<DataSourceDto>(c => c.ID == id).ToList().FirstOrDefault();
            if (dataSourceDto != null)
            {
                var dvsDto = Context.Get<DataValueSourceDto>(dv => dv.DataSourceID == id).ToList();
                foreach (var dv in dvsDto)
                {
                    Context.Repository<DataValueSourceDto>().Delete(dv);
                }

                Context.Repository<DataSourceDto>().Delete(dataSourceDto);
                Context.Commit();

                response.Data = true;
                return response;
            }
            response.Error = new[] { "DataSource provided does not exist." };
            return response;
        }
        
        #endregion

        #region From

        public ResponseData<List<Form>> GetFormList()
        {
            var response = new ResponseData<List<Form>>();
            var result = Context.Get<FormDto>().ToList();

            response.Data = result.Select(f => new Form { ID = f.ID, Name = f.Name }).ToList();

            return response;
        }

        public ResponseData<Form> GetFormById(int id)
        {
            var response = new ResponseData<Form>();
            var result = Context.Get<FormDto>(f => f.ID == id).ToList().FirstOrDefault();

            if (result != null)
            {
                response.Data = new Form { ID = result.ID, Name = result.Name };
                return response;
            }

            response.Error = new[] { "Invalid Form id" };
            return response;
        }

        public ResponseData<bool> AddForm(Form form)
        {
            var response = new ResponseData<bool>();

            //TODO: Add validation logic for Form
            //if valid then
            var formDto = new FormDto();
            formDto.Name = form.Name.ToUpper();

            Context.Repository<FormDto>().Add(formDto);
            Context.Commit();

            response.Data = true;
            return response;
        }

        public ResponseData<Form> UpdateForm(Form form)
        {
            var response = new ResponseData<Form>();

            //TODO: Add validation logic for Form
            //if valid then

            FormDto formDto = Context.Get<FormDto>(p => p.ID == form.ID).ToList().FirstOrDefault();

            if (formDto != null)
            {
                formDto.Name = form.Name.ToUpper();

                Context.Repository<FormDto>().Update(formDto);
                Context.Commit();
                response = GetFormById(form.ID);

                return response;
            }
            response.Error = new[] { "Form provided does not exist." };
            return response;
        }

        public ResponseData<bool> DeleteForm(int id)
        {
            var response = new ResponseData<bool>();

            FormDto formDto = Context.Get<FormDto>(c => c.ID == id).ToList().FirstOrDefault();
            if (formDto != null)
            {
                try
                {
                    Context.Repository<FormDto>().Delete(formDto);
                    Context.Commit();

                    response.Data = true;
                    return response;
                }
                catch (Exception ex)
                {
                    response.Data = false;
                    response.Error = new[] { "Custom form is in use" };
                    return response;
                }
            }
            response.Error = new[] { "Form provided does not exist." };
            return response;
        }

        #endregion

        #region DataValue

        public ResponseData<List<DataValue>> GetDataValueList()
        {
            var response = new ResponseData<List<DataValue>>();
            var result = Context.Get<DataValueSourceDto>().Include(f => f.DataSource).ToList();

            var dataValues = result.Select(dv => new DataValue
            {
                ID = dv.ID,
                Name = dv.Name,
                DataSourceID = dv.DataSourceID,
                Value = dv.Value,
                DataSourceName = dv.DataSource.Name
            }).ToList();

            response.Data = dataValues;

            return response;
        }

        public ResponseData<List<DataValue>> GetDataValueByDataList(int dataSourceId)
        {
            var response = new ResponseData<List<DataValue>>();
            var result = Context.Get<DataValueSourceDto>(dl => dl.DataSourceID == dataSourceId).Include(f => f.DataSource).ToList();

            var dataValues = result.Select(dv => new DataValue
            {
                ID = dv.ID,
                Name = dv.Name,
                DataSourceID = dv.DataSourceID,
                Value = dv.Value,
                DataSourceName = dv.DataSource.Name
            }).ToList();

            response.Data = dataValues;

            return response;
        }

        public ResponseData<DataValue> GetDataValueById(int id)
        {
            var response = new ResponseData<DataValue>();
            var result = Context.Get<DataValueSourceDto>(f => f.ID == id).Include(f => f.DataSource).ToList().FirstOrDefault();

            if (result != null)
            {
                response.Data = new DataValue
                {
                    ID = result.ID,
                    Name = result.Name,
                    DataSourceID = result.DataSourceID,
                    DataSourceName = result.DataSource.Name,
                    Value = result.Value
                };
                return response;
            }

            response.Error = new[] { "Invalid DataValue id" };
            return response;
        }

        public ResponseData<bool> AddDataValue(DataValue valueSource)
        {
            var response = new ResponseData<bool>();

            //TODO: Add validation logic for DataValue
            //if valid then
            var dataValueDto = new DataValueSourceDto();
            dataValueDto.Name = valueSource.Name.ToUpper();
            dataValueDto.DataSourceID = valueSource.DataSourceID;
            dataValueDto.Value = valueSource.Value;

            Context.Repository<DataValueSourceDto>().Add(dataValueDto);
            Context.Commit();

            response.Data = true;
            return response;
        }

        public ResponseData<DataValue> UpdateDataValue(DataValue valueSource)
        {
            var response = new ResponseData<DataValue>();

            //TODO: Add validation logic for DataValue
            //if valid then

            DataValueSourceDto valueSourceDto = Context.Get<DataValueSourceDto>(p => p.ID == valueSource.ID).ToList().FirstOrDefault();

            if (valueSourceDto != null)
            {
                valueSourceDto.Name = valueSource.Name.ToUpper();
                valueSourceDto.DataSourceID = valueSource.DataSourceID;
                valueSourceDto.Value = valueSource.Value;

                Context.Repository<DataValueSourceDto>().Update(valueSourceDto);
                Context.Commit();
                response = GetDataValueById(valueSource.ID);

                return response;
            }
            response.Error = new[] { "DataValue provided does not exist." };
            return response;
        }

        public ResponseData<bool> DeleteDataValue(int id)
        {
            var response = new ResponseData<bool>();

            DataValueSourceDto dataValueSourceDto = Context.Get<DataValueSourceDto>(c => c.ID == id).ToList().FirstOrDefault();
            if (dataValueSourceDto != null)
            {
                Context.Repository<DataValueSourceDto>().Delete(dataValueSourceDto);
                Context.Commit();

                response.Data = true;
                return response;
            }
            response.Error = new[] { "DataValue provided does not exist." };
            return response;
        }

        #endregion

        #region FormDetails

        public ResponseData<List<FormDesign>> GetCustomFormList(int id)
        {
            var response = new ResponseData<List<FormDesign>>();
            var result = Context.Get<FormDesignDto>(f => f.FormID == id).Include(f => f.Form).Include(f => f.DataSource).ToList();

            response.Data =
                result.Select(
                    fd =>
                        new FormDesign
                        {
                            ID = fd.ID,
                            ControlName = fd.ControlName,
                            ControlType = fd.ControlType,
                            DataSourceID = fd.DataSourceID,
                            DisplayOrder = fd.DisplayOrder,
                            FormID = fd.FormID,
                            LabelText = fd.LabelText,
                            FormName = fd.Form == null ? string.Empty : fd.Form.Name,
                            DataSourceName = fd.DataSource == null ? string.Empty : fd.DataSource.Name
                        }).ToList();

            return response;
        }

        public ResponseData<FormDesign> GetCustomFormById(int id)
        {
            var response = new ResponseData<FormDesign>();
            var fd = Context.Get<FormDesignDto>(f => f.ID == id).Include(f => f.DataSource).Include(f => f.Form).ToList().FirstOrDefault();

            if (fd != null)
            {
                response.Data = new FormDesign
                {
                    ID = fd.ID,
                    FormName = fd.Form.Name,
                    ControlName = fd.ControlName,
                    ControlType = fd.ControlType,
                    DataSourceID = fd.DataSourceID,
                    DisplayOrder = fd.DisplayOrder,
                    FormID = fd.FormID,
                    LabelText = fd.LabelText,
                    DataSourceName = fd.DataSource == null ? string.Empty : fd.DataSource.Name
                };
                return response;
            }

            response.Error = new[] { "Invalid FormDetail id" };
            return response;
        }

        public ResponseData<bool> AddCustomForm(FormDesign formDetail)
        {
            var response = new ResponseData<bool>();

            //TODO: Add validation logic for FormAnswer
            //if valid then
            var formDetailDto = new FormDesignDto()
            {
                ControlName = formDetail.ControlName,
                ControlType = formDetail.ControlType,
                DataSourceID = formDetail.DataSourceID,
                DisplayOrder = formDetail.DisplayOrder,
                FormID = formDetail.FormID,
                LabelText = formDetail.LabelText
            };

            Context.Repository<FormDesignDto>().Add(formDetailDto);
            Context.Commit();

            response.Data = true;
            return response;
        }

        public ResponseData<FormDesign> UpdateCustomForm(FormDesign formDetail)
        {
            var response = new ResponseData<FormDesign>();

            //TODO: Add validation logic for FormDetail
            //if valid then

            FormDesignDto formDetailDto = Context.Get<FormDesignDto>(p => p.ID == formDetail.ID).ToList().FirstOrDefault();

            if (formDetailDto != null)
            {
                formDetailDto.ControlName = formDetail.ControlName;
                formDetailDto.ControlType = formDetail.ControlType;
                formDetailDto.DataSourceID = formDetail.DataSourceID;
                formDetailDto.DisplayOrder = formDetail.DisplayOrder;
                formDetailDto.FormID = formDetail.FormID;
                formDetailDto.LabelText = formDetail.LabelText;

                Context.Repository<FormDesignDto>().Update(formDetailDto);
                Context.Commit();
                response = GetCustomFormById(formDetail.ID);

                return response;
            }
            response.Error = new[] { "FormDetail provided does not exist." };
            return response;
        }

        public ResponseData<bool> DeleteFormDetail(int id)
        {
            var response = new ResponseData<bool>();

            FormDesignDto formDesignDto = Context.Get<FormDesignDto>(c => c.ID == id).ToList().FirstOrDefault();
            if (formDesignDto != null)
            {
                Context.Repository<FormDesignDto>().Delete(formDesignDto);
                Context.Commit();

                response.Data = true;
                return response;
            }
            response.Error = new[] { "FormDetail provided does not exist." };
            return response;
        }

        #endregion

        #region ControlList

        public ResponseData<List<Control>> GetControlList()
        {
            var response = new ResponseData<List<Control>>();
            var result = Context.Get<ControlsDto>().ToList();

            response.Data =
                result.Select(
                    ctrl =>
                        new Control
                        {
                            ID = ctrl.ID,
                            Name = ctrl.Name
                        }).ToList();

            return response;
        }


        public ResponseData<List<RenderControl>> GetCustomFormControls(int formId)
        {
            var response = new ResponseData<List<RenderControl>>();
            var fieldList = Context.Get<FormDesignDto>(f => f.FormID == formId).Include(f => f.DataSource).ToList();

            response.Data = fieldList.Select(f =>
                new RenderControl
                             {
                                 ID = f.ID,
                                 FormID = f.FormID,
                                 DisplayOrder = f.DisplayOrder ?? 0,
                                 ControlType = f.ControlType,
                                 ControlName = f.ControlName,
                                 QuestionText = f.LabelText,
                                 DataSources = f.DataSourceID.HasValue ? GetDataSourceForCustomFormControls(f.DataSourceID.Value).Data : null
                             }).ToList();

            return response;
        }

        public ResponseData<List<DataValue>> GetDataSourceForCustomFormControls(int datasourceID)
        {
            var response = new ResponseData<List<DataValue>>();
            var dataValueList = Context.Get<DataValueSourceDto>(dv => dv.DataSourceID == datasourceID).ToList();
            response.Data = dataValueList.Select(dv => new DataValue
                            {
                                ID = dv.ID,
                                Name = dv.Name,
                                DataSourceID = dv.DataSourceID,
                                Value = dv.Value
                            }).ToList();

            return response;
        }

        #endregion
    }
}